﻿// ConsoleApplication1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include "pow_globs.h"
#include <stdio.h>
#include <stdlib.h>

void exp10(Sint x, Uint *y)
{
    /* Lookup tables padded with zeroes on positions corresponding */
    /* to unvalid input values */
    Uint lookup[16] = { 0x00000000, 0x00000000, 0x00000000,
                        0x00000000, 0x00000000, 0x00000000,
                        0xA0000000, 0x80000000, 0xCCCCCCCC,
                        0xA3D70A3D, 0x83126E97, 0xD1B71758,
                        0xA7C5AC47, 0x8637BD05, 0xD6BF94D5,
                        0xABCC7711
                      };
    Uint lookup2[8] = { 0x10000000, 0x15561A92, 0x1C73D51C,
                        0x25F1258E, 0x3298B076, 0x4378B054,
                        0x59F9802D, 0x77FBAAB4
                      };

    /* Polynomial coefficients. c[6] is corrected upwards to */
    /* compensate the result for truncation bias in the alg. */
    Uint       c[7] = { 0x00000F4F, 0x0001113D, 0x0012BF85,
                        0x01046F98, 0x0A9A9286, 0x49AEC6EC,
                        0x80000000 + 8
                      };

    Sint shft[16] = { 0, 0, 0, 0, 0, 0, 0, 3, 7, 10, 13, 17, 20, 23, 27, 30 };

    Uint  a = 0;
    Uint  m = 0;
    Uint  m2 = 0;
    Uint  m3 = 0;
    Uint  m4 = 0;
    Uint  m5 = 0;
    Uint  m6 = 0;
    Uint  lp = 0;
    Uint  frac = 0;
    Uint  ro = 0;
    Uint  ro1 = 0;
    Uint  *lookup_ptr = OSP_NULLP;
    Uint  *lookup_ptr2 = OSP_NULLP;
    Sint  ip = 0;
    Sint  *shift_ptr = OSP_NULLP;

    /* extract integer part */
    ip = x >> 28;

    /* chose the right entry in the lookup table */
    lookup_ptr = lookup + 7 - ip;

    /* chose the corresponding entry in the shift table */
    shift_ptr = shft + 7 - ip;

    /* extract fractional part */
    m = x << 4;

    /* calculation of 10^(fractional part):10^frac = 10^(n/8 + rest) */
    /* = 10^(n/8)*10^rest. 10^n/8 is found in lookup2 and 10^rest is */
    /* approximated with a polynomial of degree 6                    */

    /* chose entry in lookup2 table */
    lp = (x & 0x0E000000) >> 25;
    lookup_ptr2 = lookup2 + lp;

    /* cancel the "n/8" bits, m = rest = 0.. 0.125      */
    m = m << 3;   /* map to 0..1 in Q32 unsigned */
    m = m >> 1;   /* change Q32 to 0..1 in Q31   */

    /* powers of m used in polynomial calculation */
    m2 = MPYU_Q31(m, m);
    m3 = MPYU_Q31(m2, m);
    m4 = MPYU_Q31(m3, m);
    m5 = MPYU_Q31(m4, m);
    m6 = MPYU_Q31(m5, m);

    /* Evaluate the polynomial @ m. The coeffs are in Q32 unsigned  */
    /* Only one instruction is needed for m6*c[6] because there is  */
    /* no high part in c[0]. In the same manner, m5*c[1] is         */
    /* calculated using two mpy's since lo(m5)*hi(c[1]) makes no    */
    /* contribution.                                                */
    a = _mpyhlu(m6, c[0]);
    a += (_mpyhlu(m5, c[1]));
    a >>= 16;
    a += _mpyhu(m5, c[1]);
    a += MPYU_Q32(m4, c[2]);
    a += MPYU_Q32(m3, c[3]);
    a += MPYU_Q32(m2, c[4]);
    a += MPYU_Q32(m, c[5]);
    a += c[6];

    /* frac = 10^(n/8)*10^rest */
    frac = MPYU_Q31(*lookup_ptr2, a);

    /* Rounding instead of truncation to improve accuracy */
    ro1 = (Uint)0x1 << (*shift_ptr);
    ro = ro1 >> 1;

    /* Now do 10^x = 10^int*10^frac; frac and lookup entry are */
    /* in Q32. Add 1/2 lsb, shift and do next iteration.       */
    *y = (MPYU_Q32(*lookup_ptr, frac) + ro) >> (*shift_ptr);

    return;
}

Sint fdl_L_shl(Sint L_var1, Sshort var2)
{
    Sint L_var_out;
    if (var2 <= 0)
    {
        L_var_out = L_var1 >> (-var2);
    }
    else
    {
        for (; var2 > 0; var2--)
        {
            if (L_var1 > (Sint)0X3fffffff)
            {
                L_var1 = 0x7fffffff;
                break;
            }
            else if (L_var1 < (Sint)0xc0000000)
            {
                L_var1 = (Sint)0x80000000;
                break;
            }
            else
            {
                L_var1 *= 2;
            }
        }
        L_var_out = L_var1;
    }
    return (L_var_out);
}

void fxx_exp10(Sint x, Uint* y, Ushort x_dec, Ushort y_dec)
{
    Sint t_s_val1 = 0;
    Uint t_val1 = 0;

    if (x_dec >= 28)
    {
        t_s_val1 = x >> (x_dec - 28);
    }
    else
    {
        t_s_val1 = x << (28 - x_dec);
    }

    exp10(t_s_val1, &t_val1);

    if (y_dec >= 24)
    {
        *y = t_val1 << (y_dec - 24);
    }
    else
    {
        *y = t_val1 >> (24 - y_dec);
    }

    return;
}

Ushort fdl_pow_amp(Sshort x, Ushort y_dec, Ushort a_iq_nom_tx, Sshort p_out_tx_norm)
{
    Ushort  tx_amp = 0;
    Sint    val1 = 0;
    Sint    val2 = 0;
    Uint    temp_val = 0;
    Sint    input = 0;
    Sint    temp_p_norm = p_out_tx_norm;

    /*val1 = x * 0.1/20, x is Q(16,16),328 is 0.005 in Q(16,0)*/
    val1 = x * 328; /*Q(32, 16)*/
    val1 = fdl_L_shl(val1, 12); /*val1 in Q(32,4)*/

    /*val2 = p_out_tx_norm / 20, p_out_tx_norm is Q(16,8), 3277 is 0.05 in Q(16,0)*/
    val2 = temp_p_norm * 3277; /*Q(32,16)*/
    val2 = fdl_L_shl(val2, 4); /*val2 in Q(32,4)*/

    input = (Sint)(val1 - val2);

    fxx_exp10(input, &temp_val, 28, 24);

    /*temp_val is Q(32,8), a_iq_nom_tx is Q(16,3)*/
    temp_val = MDL_MPYU16_32(a_iq_nom_tx, temp_val);/*Q(32,11)*/
    temp_val = temp_val >> (21 - y_dec);

    tx_amp = (Ushort)temp_val; /*Q(16,3)*/

    return (tx_amp);
}

int main()
{
    Ushort p_temp = gdl_2560log_ante[64];
    Sshort p_out_tx_norm_trb = 0xffd9;      /*具体代表含义可参考向量需求文档*/
    Sshort a_iq_norm_tx_trb = 8230;         /*具体代表含义可参考向量需求文档*/
    Sshort a_out;                           /*arm侧出口A值*/
    Sshort p_in_form_lmt = 170;             /*LMT-B配置的信号功率*/
    Ushort a_iq_norm_tx = 0;                /*Q(16,3)，具体代表含义可参考向量需求文档*/
    Sshort p_out_tx_norm = 0;               /*1/256dBm，具体代表含义可参考向量需求文档*/

    /*for 100M 30kHz Cell，P0' = P0 + 256*10lg(ante_num) - 256*10lg3276), in 1/256dBm*/
    /*256*10lg3276 = 8999*/
    p_out_tx_norm = p_out_tx_norm_trb + p_temp;
    /*for 100M 30kHz Cell，Af = At * sqrt(4096/3276) * 4，Q(16,1)->Q(16,3)*/
    /* sqrt(4096/3276)=18320 in Q(16,2), Q(16,3) * Q(16,2) >> 14->Q(18,5), Ushort->Q(16,3),0x2000 means round*/
    a_iq_norm_tx = (Ushort)((a_iq_norm_tx_trb * 18320 + 0x2000) >> 14);


    a_out = fdl_pow_amp(p_in_form_lmt, 13, a_iq_norm_tx, p_out_tx_norm);

    printf("a_out = %d \n", a_out);

    return 0;
}

